package sunyu.quartz.common;

import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * 动态注册schedulerFactoryBean
 * <p>
 * 作用是将spring上下文中，所有CronTriggerFactoryBean.class类型的bean找到，动态注入triggers
 *
 * @author 孙宇
 */
public class CommonSchedulerFactoryBean implements ApplicationContextAware {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private ApplicationContext applicationContext;

    @Value("${quartz.applicationContextSchedulerContextKey}")
    private String applicationContextSchedulerContextKey;
    @Value("${quartz.waitForJobsToCompleteOnShutdown}")
    private String waitForJobsToCompleteOnShutdown;
    @Value("${quartz.schedulerName}")
    private String schedulerName;
    @Value("${quartz.dataSource}")
    private String dataSource;
    @Value("${quartz.startupDelay}")
    private String startupDelay;
    @Value("${quartz.overwriteExistingJobs}")
    private String overwriteExistingJobs;
    @Value("${quartz.autoStartup}")
    private String autoStartup;
    @Value("${quartz.scheduler.instanceName}")
    private String instanceName;
    @Value("${quartz.scheduler.instanceId}")
    private String instanceId;
    @Value("${quartz.jobStore.class}")
    private String jobStoreClass;
    @Value("${quartz.jobStore.tablePrefix}")
    private String tablePrefix;
    @Value("${quartz.jobStore.isClustered}")
    private String isClustered;
    @Value("${quartz.jobStore.clusterCheckinInterval}")
    private String clusterCheckinInterval;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void init() {
        logger.info("动态注册SchedulerFactoryBean，自动扫描Applicationcontext中，所有类型为CronTriggerFactoryBean的类，注入到SchedulerFactoryBean中");

        Map<String, CronTriggerFactoryBean> beans = applicationContext.getBeansOfType(CronTriggerFactoryBean.class);
        List<Trigger> triggers = new ArrayList<>();//所有需要动态注入的触发任务
        for (Map.Entry<String, CronTriggerFactoryBean> entry : beans.entrySet()) {
            triggers.add(entry.getValue().getObject());
        }

        Properties properties = new Properties();
        /*properties.put("org.quartz.scheduler.rmi.export", "false");
        properties.put("org.quartz.scheduler.rmi.proxy", "false");
        properties.put("org.quartz.scheduler.wrapJobExecutionInUserTransaction", "false");
        properties.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        properties.put("org.quartz.threadPool.threadCount", "10");
        properties.put("org.quartz.threadPool.threadPriority", "5");
        properties.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", "true");
        properties.put("org.quartz.jobStore.misfireThreshold", "60000");*/
        properties.put("org.quartz.scheduler.instanceName", instanceName);
        properties.put("org.quartz.scheduler.instanceId", instanceId);
        properties.put("org.quartz.jobStore.class", jobStoreClass);
        properties.put("org.quartz.jobStore.tablePrefix", tablePrefix);
        properties.put("org.quartz.jobStore.isClustered", isClustered);
        properties.put("org.quartz.jobStore.clusterCheckinInterval", clusterCheckinInterval);

        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(SchedulerFactoryBean.class);
        beanDefinitionBuilder.addPropertyValue("triggers", triggers);
        beanDefinitionBuilder.addPropertyValue("schedulerName", schedulerName);
        beanDefinitionBuilder.addPropertyReference("dataSource", dataSource);
        beanDefinitionBuilder.addPropertyValue("applicationContextSchedulerContextKey", applicationContextSchedulerContextKey);
        beanDefinitionBuilder.addPropertyValue("waitForJobsToCompleteOnShutdown", waitForJobsToCompleteOnShutdown);
        beanDefinitionBuilder.addPropertyValue("startupDelay", startupDelay);
        beanDefinitionBuilder.addPropertyValue("overwriteExistingJobs", overwriteExistingJobs);
        beanDefinitionBuilder.addPropertyValue("autoStartup", autoStartup);
        beanDefinitionBuilder.addPropertyValue("quartzProperties", properties);

        beanDefinitionBuilder.setDestroyMethodName("destroy");

        defaultListableBeanFactory.registerBeanDefinition("schedulerFactoryBean", beanDefinitionBuilder.getRawBeanDefinition());//注册到spring
    }

}
